library ieee;
 use ieee.std_logic_1164.all;
 use ieee.std_logic_unsigned.all;
 use ieee.std_logic_arith.all;

library work;
    use work.router_pack.all;
    use work.env_pack.all;

-------------------------------------------------------------------------
    
entity injector_if is

port(
    -- General Signals: --
    RESET   : in std_logic;
    CLK     : in std_logic;
    
    -- Output Port i/f: --
    RO      : out std_logic;
    AO      : in std_logic;
    DO      : out std_logic_vector(flit_size_c-1 downto 0);
    
    -- Packet Info: --
    PACKET_REQ      : in std_logic;
    SL              : in std_logic_vector(msl_ind_width-1 downto 0);
    VC              : in std_logic_vector(vc_width-1 downto 0);
    SOURCE_ROUTING  : in std_logic_vector(e_flit_data_width_c-1 downto 0);
    PACKET_SIZE     : in std_logic_vector(e_packet_size_width_c-1 downto 0);
    PACKET_ID       : in std_logic_vector(e_packet_id_width_c-1 downto 0);
    PACKET_SENT     : out std_logic;
    HEADER_SENT	    : out std_logic
);
    
end injector_if;

-------------------------------------------------------------------------

architecture injector_if_arch of injector_if is

-- Internal Signals --

   signal flit_count        : std_logic_vector(e_packet_size_width_c-1 downto 0);
   signal in_tx_ind         : std_logic := '0'; -- indication that a packet is being transmitted
   signal packet_sent_out   : std_logic := '0';
   signal header_sent_out		 : std_logic := '0';
   signal ao_samp			    : std_logic := '0';

-- Implementation --

begin
    
   flit_tx: process(RESET, CLK, PACKET_REQ)
   variable flit_data	: std_logic_vector(e_flit_data_width_c-1 downto 0);
   variable packet_sent_in   : std_logic := '0';
   variable header_sent_in   : std_logic := '0';
   begin
        
      if (CLK'event and CLK='1') then

         if (RESET = '1') then
            RO <= '0';
            DO <= conv_std_logic_vector(0, flit_size_c);
            PACKET_SENT <= '0';
            packet_sent_out <= '0';
            header_sent_out <= '0';
         
         elsif (PACKET_REQ='1') then
            
            if (packet_sent_in='1') then
              	packet_sent_in := '0';
            
            -- if Router Acked the requested flit
            -- bugfix: AO needs to be viewed only on its fall
            elsif (AO='0' and ao_samp='1') then

               if (flit_count=PACKET_SIZE-1) then       
	           packet_sent_in := '1';
               end if;
               
               -- increase the flit count that was sent
               flit_count <= flit_count + 1;	--fixme: shouldn't be dependant only on ao
              	
            -- if this is a new packet
            elsif (in_tx_ind = '0') then
               flit_count <= conv_std_logic_vector(0, e_packet_size_width_c);
               in_tx_ind <= '1';
                 
               -- send a header flit
               DO <= VC & SL & "01" & SOURCE_ROUTING;
               RO <= '1';
               header_sent_in := '1';
            
            -- if there are data flits left to be sent
            -- and the Router is ready for the next flit
            elsif ((flit_count < PACKET_SIZE) and (flit_count > conv_std_logic_vector(0, e_packet_size_width_c)) and (AO='0')) then
               RO <= '1';
               
               -- prepare flit data from parts of the PacketID
               case conv_integer(flit_count) is
                  when 1 => flit_data := PACKET_ID(1*e_flit_data_width_c-1 downto 0*e_flit_data_width_c);
                  when 2 => flit_data := PACKET_ID(2*e_flit_data_width_c-1 downto 1*e_flit_data_width_c);
--                  when "0010" => flit_data <= PACKET_ID(2*e_flit_data_width_c-1 downto 1*e_flit_data_width_c);
--                  when "0011" => flit_data <= PACKET_ID(3*e_flit_data_width_c-1 downto 2*e_flit_data_width_c);
--                  when "0100" => flit_data <= PACKET_ID(4*e_flit_data_width_c-1 downto 3*e_flit_data_width_c);
--                  when "0101" => flit_data <= PACKET_ID(5*e_flit_data_width_c-1 downto 4*e_flit_data_width_c);
--                  when "0110" => flit_data <= PACKET_ID(6*e_flit_data_width_c-1 downto 5*e_flit_data_width_c);
--                  when "0111" => flit_data <= PACKET_ID(7*e_flit_data_width_c-1 downto 6*e_flit_data_width_c);
--                  when "1000" => flit_data <= PACKET_ID(8*e_flit_data_width_c-1 downto 7*e_flit_data_width_c);
--                  when "1001" => flit_data <= PACKET_ID(9*e_flit_data_width_c-1 downto 8*e_flit_data_width_c);
--                  when "1010" => flit_data <= PACKET_ID(10*e_flit_data_width_c-1 downto 9*e_flit_data_width_c);
--                  when "1011" => flit_data <= PACKET_ID(11*e_flit_data_width_c-1 downto 10*e_flit_data_width_c);
--                  when "1100" => flit_data <= PACKET_ID(12*e_flit_data_width_c-1 downto 11*e_flit_data_width_c);
--                  when "1101" => flit_data <= PACKET_ID(13*e_flit_data_width_c-1 downto 12*e_flit_data_width_c);
--                  when "1110" => flit_data <= PACKET_ID(14*e_flit_data_width_c-1 downto 13*e_flit_data_width_c);
--                  when "1111" => flit_data <= PACKET_ID(15*e_flit_data_width_c-1 downto 14*e_flit_data_width_c);
                  when others => flit_data := conv_std_logic_vector(0, e_flit_data_width_c);
               end case;
               
               if (AO='0') then       
	               	-- if this is a body flit
 	              		if (flit_count < PACKET_SIZE-1) then
                   
  	              			-- Send a Body flit with a part of a PacketID
				DO <= VC & SL & "00" & flit_data;
                    
               				-- if this is a Tail flit
               			else
                  				-- Send a Tail flit with a part of a PacketID
                  				DO <= VC & SL & "10" & flit_data;
               			end if; -- (flit_count < PACKET_SIZE-1)
               	end if; -- (AO='0')
            end if; -- ((flit_count < PACKET_SIZE) and ...
              
         end if; -- (PACKET_REQ='1')
          
         if (packet_sent_out='1') then
             packet_sent_in := '0';
         end if;
         
         if (header_sent_out='1') then
         		header_sent_in := '0';
         end if;

         PACKET_SENT <= packet_sent_in;
         packet_sent_out <= packet_sent_in;
         
         HEADER_SENT <= header_sent_in;
         header_sent_out <= header_sent_in;
         
         -- if Router Acked the requested flit
       	 if (AO='1') then
      		RO <= '0';
      	 end if;
      	 
      	 if(packet_sent_out='1') then
	      	 -- If this is the Tail flit
  		if (flit_count=PACKET_SIZE) then                   
         			in_tx_ind <= '0';
        		end if;
        	end if;

      	 ao_samp <= AO;

      end if; -- (CLK'event and CLK='1')
        
   end process; -- flit_tx
    
end injector_if_arch;